package com.ehotting.edsta.circuitDesign.gen;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.ehotting.edsta.circuitDesign.bean.AllMapBean;
import com.ehotting.edsta.circuitDesign.bean.CircuitElementBean;
import com.ehotting.edsta.circuitDesign.bean.CircuitGroupBean;
import com.ehotting.edsta.circuitDesign.bean.ProCodeName;
import com.ehotting.edsta.circuitDesign.bean.request.RequestCodeExecute;
import com.ehotting.edsta.circuitDesign.domain.EsCircuit;
import com.ehotting.edsta.circuitDesign.domain.EsCircuitType;
import com.ehotting.edsta.circuitDesign.enums.*;
import com.ehotting.edsta.circuitDesign.gen.element.helper.NumberHelper;
import com.ehotting.edsta.circuitDesign.service.IEsCircuitCodeDataService;
import com.ehotting.edsta.circuitDesign.service.IEsCircuitCodeDataTemplateService;
import com.ehotting.edsta.circuitDesign.service.IEsCircuitService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class CircuitGroupHelper {

    @Autowired
    private IEsCircuitService esCircuitService;

    public List<CircuitGroupBean> convert(EsCircuitType circuitType,
                                          List<CircuitElementBean> circuitAndElementList,
                                          AllMapBean contextMap){
        //加载电路属性
        loadCircuitProp(circuitAndElementList);
        if(CircuitTypeEnum.SENSOR == circuitType.getCircuitType()){
           return handleSensor( circuitAndElementList,  contextMap);
        }else{
            return convert(circuitAndElementList);
        }
    }

    /**
     * 通道匹配
     * @param circuitAndElementList
     * @param contextMap
     * @return
     */
    private List<CircuitGroupBean> handleSensor(List<CircuitElementBean> circuitAndElementList, AllMapBean contextMap){
        Map<String, Object> data = contextMap.get(CircuitTypeEnum.USER, CodeDataTypeEnum.INPUT_PARAM);
        String analogueNum = (String)data.get(RequestArgumentEnum.ANALOGUE_NUM.getCode());
        String digitalNum = (String)data.get(RequestArgumentEnum.DIGITAL_NUM.getCode());
        List<CircuitGroupBean> circuitGroupList = new ArrayList<>();

        /**
         * FPGA控制器类型去除模拟输出
         */
//        String controller = ProCodeName.Controller;
//        String contr = data.get(controller).toString();
//        List<CircuitElementBean> newCEL = new ArrayList<>();
//        if(contr.contains("FPGA")){
//            for(CircuitElementBean c : circuitAndElementList){
//                if(c.getCircuit().getProp().get(ProCodeName.Output_Type).toString().contains("1")){
//                    newCEL.add(c);
//                }
//            }
//            circuitAndElementList = newCEL;
//        }

        /**
         * 模拟通道匹配---通道数大于0
         */
        if(NumberHelper.parseInteger(analogueNum)>0){
            List<RequestCodeExecute.AnalogueData> analogueList =
                    (List<RequestCodeExecute.AnalogueData>)data.get(RequestArgumentEnum.ANALOGUE.getCode());

            List<CircuitElementBean> circuitAnalogueList = circuitAndElementList.stream().filter(
                    t->t.getChannelTypeInput()== ChannelTypeInputEnum.ANALOGUE).collect(Collectors.toList());

            circuitGroupList.addAll(handleAnalogue(circuitAnalogueList,analogueList));
        }

        /**
         * 数字通道匹配---通道数大于0
         */
        if(NumberHelper.parseInteger(digitalNum)>0){

            //用户输入的数字通道参数
            List<RequestCodeExecute.DigitalData> digitalList =
                    (List<RequestCodeExecute.DigitalData>)data.get(RequestArgumentEnum.DIGITAL.getCode());

            //符合条件的传感电路
            List<CircuitElementBean> circuitDigitalList = circuitAndElementList.stream().filter(
                    t->t.getChannelTypeInput()== ChannelTypeInputEnum.DIGITAL).collect(Collectors.toList());

            circuitGroupList.addAll(handleDigital(circuitDigitalList,digitalList));
        }

        return circuitGroupList;
    }

    private List<CircuitGroupBean> convert(List<CircuitElementBean> circuitAndElementList){
        List<CircuitGroupBean> circuitGroupList = new ArrayList();
        for(CircuitElementBean circuitElement : circuitAndElementList){
            CircuitGroupBean newCircuitGroup = new CircuitGroupBean();

            newCircuitGroup.put(circuitElement.getCircuit().getId(),circuitElement);
            newCircuitGroup.setSignalType(circuitElement.getCircuit().getSignalType());

            circuitGroupList.add(newCircuitGroup);
        }
        return circuitGroupList;
    }


    /**
     * 模拟通道匹配---按类型进行匹配
     * @param circuitAndElementList
     * @param analogueList
     * @return
     */
    private List<CircuitGroupBean> handleAnalogue(List<CircuitElementBean> circuitAndElementList,
                                List<RequestCodeExecute.AnalogueData> analogueList){

        Map<SignalTypeEnum,List<CircuitElementBean>> signalTypeCircuitListMap = handleAnalogueCircuitAndElementList( circuitAndElementList);
        Map<SignalTypeEnum,Integer> signalTypeCountMap = handleAnalogueCount( analogueList);
        List<CircuitGroupBean> circuitGroupList = new ArrayList();
        SignalTypeEnum[] signalTypeArray = SignalTypeEnum.values();
        for(SignalTypeEnum signalType : signalTypeArray) {

            if (!signalTypeCountMap.containsKey(signalType) || signalTypeCountMap.get(signalType) <= 0) {
                continue;
            }

            List<CircuitElementBean> circuitElementList = signalTypeCircuitListMap.get(signalType);
            AssertUtil.isTrue(!CollectionUtil.isEmpty(circuitElementList),"数据采集电路模块(模拟)["+signalType.getName()+"]没有符合的电路模块");

            List<RequestCodeExecute.InputChannel> analogueDataList = new ArrayList<>();
            for(RequestCodeExecute.AnalogueData a:analogueList){
                if(Integer.valueOf(a.getAnaloguetype()).equals(signalType.getValue()) ){
                    analogueDataList.add(a);
                }
            }

            List<CircuitGroupBean> circuitGroupBeans = CircuitAllocationHelper.invoke(analogueDataList, circuitElementList);

            AssertUtil.isTrue(!CollectionUtil.isEmpty(circuitGroupBeans),"数据采集电路模块(模拟)["+signalType.getName()+"]没有符合的电路模块");

            circuitGroupBeans.forEach(c->{
                c.setSignalType(signalType);
            });
            circuitGroupList.addAll(circuitGroupBeans);

        }
        return circuitGroupList;
    }

    /**
     * 数字通道匹配---按类型进行匹配
     * @param circuitAndElementList
     * @param analogueList
     * @return
     */
    private List<CircuitGroupBean> handleDigital(List<CircuitElementBean> circuitAndElementList,
                                                  List<RequestCodeExecute.DigitalData> analogueList){

        Map<DigitalTypeEnum,List<CircuitElementBean>> digitalTypeCircuitListMap = handleDigitalCircuitAndElementList( circuitAndElementList);
        List<CircuitGroupBean> circuitGroupList = new ArrayList();
        DigitalTypeEnum[] digitalTypeArray = DigitalTypeEnum.values();
        Map<String, List<RequestCodeExecute.DigitalData>> collectByInType = analogueList.stream()
                .collect(Collectors.groupingBy(RequestCodeExecute.DigitalData::getIntype));

        for(DigitalTypeEnum digitalType : digitalTypeArray) {

            List<RequestCodeExecute.DigitalData> digitalData = collectByInType.get(digitalType.getCode());
            if(digitalData == null || digitalData.size() == 0){
                continue;
            }
            List<CircuitElementBean> circuitElementList = digitalTypeCircuitListMap.get(digitalType);
            AssertUtil.isTrue(!CollectionUtil.isEmpty(circuitElementList),
                    "数据采集电路模块(数字)["+digitalType.getName()+"]没有符合的电路模块");

            List<RequestCodeExecute.DigitalData> collectInVolt6 = digitalData.stream()
                    .filter(d -> Double.valueOf(d.getInvolt()) > 5 ? true : false)
                    .collect(Collectors.toList());

            Map<String, List<RequestCodeExecute.DigitalData>> collectInVolt5 = digitalData.stream()
                    .filter(d -> Double.valueOf(d.getInvolt()) <= 5 ? true : false)
                    .collect(Collectors.groupingBy(RequestCodeExecute.DigitalData::getInvolt));

            Map<String, List<RequestCodeExecute.DigitalData>> allInVolt = new HashMap<>();
            if(collectInVolt6.size() > 0){
                allInVolt.put("6"+digitalType.getCode(),collectInVolt6);
            }
            for (String cok : collectInVolt5.keySet()){
                allInVolt.put(cok+digitalType.getCode(),collectInVolt5.get(cok));
            }

            for(String k : allInVolt.keySet()){
                List<RequestCodeExecute.InputChannel> digitalDataList = new ArrayList<>();
                digitalDataList.addAll(allInVolt.get(k));
                List<CircuitGroupBean> circuitGroupBeans = CircuitAllocationHelper.invoke(digitalDataList, circuitElementList);

                AssertUtil.isTrue(!CollectionUtil.isEmpty(circuitGroupBeans),
                        "数据采集电路模块(数字)["+digitalType.getName()+k+"]没有符合的电路模块");
                circuitGroupBeans.forEach(c->{
                    c.setSignalType(SignalTypeEnum.OTHER);
                    c.setDigitalInVolt(k);
                });
                circuitGroupList.addAll(circuitGroupBeans);
            }

        }
        return circuitGroupList;
    }

    private Map<SignalTypeEnum,List<CircuitElementBean>> handleAnalogueCircuitAndElementList(List<CircuitElementBean> circuitAndElementList){
        Map<SignalTypeEnum,List<CircuitElementBean>> signalTypeCircuitListMap = new HashMap<>();
        for(CircuitElementBean circuitElement : circuitAndElementList){

            if(!signalTypeCircuitListMap.containsKey(circuitElement.getCircuit().getSignalType())){
                signalTypeCircuitListMap.put(circuitElement.getCircuit().getSignalType(),new ArrayList<>());
            }
            signalTypeCircuitListMap.get(circuitElement.getCircuit().getSignalType()).add(circuitElement);
        }
        return  signalTypeCircuitListMap;
    }

    private Map<DigitalTypeEnum,List<CircuitElementBean>> handleDigitalCircuitAndElementList(List<CircuitElementBean> circuitAndElementList){
        Map<DigitalTypeEnum,List<CircuitElementBean>> digitalTypeCircuitListMap = new HashMap<>();
        for(CircuitElementBean circuitElement : circuitAndElementList){

            if(!digitalTypeCircuitListMap.containsKey(circuitElement.getInType())){
                digitalTypeCircuitListMap.put(circuitElement.getInType(),new ArrayList<>());
            }
            digitalTypeCircuitListMap.get(circuitElement.getInType()).add(circuitElement);
        }
        return  digitalTypeCircuitListMap;
    }

    private Map<SignalTypeEnum,Integer> handleAnalogueCount(List<RequestCodeExecute.AnalogueData> analogueList){
        SignalTypeEnum[] signalTypeArray = SignalTypeEnum.values();
        Map<SignalTypeEnum,Integer> signalTypeCountMap = new HashMap<>();
        for(SignalTypeEnum signalType : signalTypeArray){
            signalTypeCountMap.put(signalType,getAnalogueCount( analogueList, signalType));
        }
        return signalTypeCountMap;
    }

//    private Map<DigitalTypeEnum,Integer> handleDigitalCount(List<RequestCodeExecute.DigitalData> analogueList){
//        DigitalTypeEnum[] digitalTypeArray = DigitalTypeEnum.values();
//        Map<DigitalTypeEnum,Integer> digitalTypeCountMap = new HashMap<>();
//        for(DigitalTypeEnum digitalType : digitalTypeArray){
//            digitalTypeCountMap.put(digitalType,getDigitalCount( analogueList, digitalType));
//        }
//        return digitalTypeCountMap;
//    }


    private Integer getAnalogueCount(List<RequestCodeExecute.AnalogueData> analogueList,SignalTypeEnum signalType){
        int count = 0 ;
        for(RequestCodeExecute.AnalogueData analogueData: analogueList){
            if(signalType.getValue().toString().equals(analogueData.getAnaloguetype())){
                count++;
            }
        }
        return count;
    }

    private Integer getDigitalCount(List<RequestCodeExecute.DigitalData> analogueList,DigitalTypeEnum digitalType){
        int count = 0 ;
        for(RequestCodeExecute.DigitalData analogueData: analogueList){
            if(digitalType.getCode().equals(analogueData.getIntype())){
                count++;
            }
        }
        return count;
    }

    private void loadCircuitProp(List<CircuitElementBean> circuitAndElementList){
        for(CircuitElementBean circuitAndElement : circuitAndElementList){
            EsCircuit circuit = circuitAndElement.getCircuit();
            esCircuitService.loadProp(circuit);
        }
    }
}
